package controller;

import util.MoveType;
import entity.Board;
import entity.Edge;
import entity.Movable;
import entity.Move;
import entity.Poem;
import entity.Row;
import entity.Word;
import gui.BoardApplication;

/**
 * This is the connect controller.
 */
public class ConnectController {
	private Board board;
	private BoardApplication gui;

	/**
	 * Constructor of connect controller.
	 */
	public ConnectController(BoardApplication gui, Board board){
		this.board = board;
		this.gui = gui;
	}

	/**
	 * Connect two objects.
	 * Move a word, a row or a poem to connect with a word.
	 * Move a word, a row or a poem to connect with a row.
	 * Move a word, a row or a poem to connect with a poem.
	 */
	public void connect(Movable staticItem, Movable movedItem, Edge edge, boolean checkpoint){
		Move move = new Move(MoveType.CONNECT, checkpoint);
		
		if(staticItem instanceof Word){
			Word w = (Word) staticItem;
			move.addOldItem(w);

			if(movedItem instanceof Word){
				Row r = new Row(Row.nextId(), w);
				Poem p = new Poem(Poem.nextId(), r);

				move.addOldItem(movedItem);

				if(edge == Edge.TOP || edge == Edge.BOTTOM){
					p.addRow(new Row(Row.nextId(), (Word) movedItem), edge);
					p.rearrange();
				}else{
					r.addWord((Word) movedItem, edge);
				}

				board.getPoems().add(p);
				
				move.addNewItem(p);
				board.addMove(move);
			}else if(movedItem instanceof Row){
				Row r = (Row) movedItem;
				move.addOldItem(board.poemThatContains(r));
				
				Edge opposingEdge = edge == Edge.RIGHT ? Edge.LEFT : edge == Edge.LEFT ? Edge.RIGHT : null;				

				r.addWord(w, opposingEdge);
				
				move.addNewItem(board.poemThatContains(r));
				board.addMove(move);
			}else if(movedItem instanceof Poem){
				Poem p = (Poem) movedItem;
				move.addOldItem(p);

				if(p.getRows().size() == 1){
					p.getRows().get(0).addWord(w, edge);
					
					move.addNewItem(p);
					board.addMove(move);
				}
			}
		}else if(staticItem instanceof Row){
			Row r = (Row) staticItem;

			if(movedItem instanceof Word){
				Poem p = board.poemThatContains(r);
				move.addOldItem(p);
				move.addOldItem(movedItem);
				
				r.addWord((Word) movedItem, edge);				

				if(edge == Edge.LEFT && p.getRows().indexOf(r) > 0){
					r.setOffsetX(movedItem.getX() - p.getX());
				}else{
					p.rearrange();
				}
				
				move.addNewItem(p);
				board.addMove(move);
			}else if(movedItem instanceof Row){
				Poem p = board.poemThatContains((Row) movedItem);
				move.addOldItem(p);
				move.addOldItem(board.poemThatContains(r));
				
				board.getPoems().remove(p);

				r.addRow((Row) movedItem, edge);
				
				move.addNewItem(board.poemThatContains(r));
				board.addMove(move);
			}else if(movedItem instanceof Poem){
				Poem p = (Poem) movedItem;
				move.addOldItem(board.poemThatContains(r));
				move.addOldItem(p);

				if(p.getRows().size() == 1){
					r.addRow(p.getRows().get(0), edge);
					board.getPoems().remove(p);
					p.rearrange();					
				}

				move.addNewItem(board.poemThatContains(r));
				board.addMove(move);		
			}

			r.rearrange();
		}else if(staticItem instanceof Poem){
			Poem p = (Poem) staticItem;
			move.addOldItem(p);

			if(movedItem instanceof Word){
				Row r = new Row(Row.nextId(), (Word) movedItem);
				p.addRow(r, edge);
				
				move.addNewItem(p);
				board.addMove(move);
			}else if(movedItem instanceof Row){
				Row r = (Row) movedItem;
				p.addRow(r, edge);
				
				move.addNewItem(p);
				board.addMove(move);
			}else if(movedItem instanceof Poem){
				Poem p2 = (Poem) movedItem;
				move.addOldItem(p2);

				if(p.getRows().size() == 1 && p2.getRows().size() == 1){
					p.addRow(p2.getRows().get(0), edge);
					board.getPoems().remove(p2);

					move.addNewItem(p);
					board.addMove(move);
				}else if(edge == Edge.TOP || edge == Edge.BOTTOM){
					p.addPoem(p2, edge);
					board.getPoems().remove(p2);

					move.addNewItem(p);
					board.addMove(move);
				}
			}

			p.rearrange();
		}
	}

	/**
	 * Return board.
	 */
	public Board getBoard() {
		return board;
	}

	/**
	 * Return gui.
	 */
	public BoardApplication getGui() {
		return gui;
	}
}
